package com.alibaba.citrus.cr.mn.order.center.facade.function.common;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.citrus.cr.common.annotation.EpochTransactional;
import com.alibaba.citrus.cr.common.enums.ordercenter.OrderCategoryEnum;
import com.alibaba.citrus.cr.common.exception.FunctionException;
import com.alibaba.citrus.cr.common.util.ThreadPoolUtil;
import com.alibaba.citrus.cr.mn.order.center.common.util.StopWatchUtils;
import com.alibaba.citrus.cr.mn.order.center.facade.function.dataobject.AtomOrderDO;
import com.alibaba.citrus.cr.mn.order.center.facade.repository.AtomOrderQueryRepository;
import com.alibaba.citrus.cr.mn.order.center.facade.repository.AtomOrderRepository;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.epoch.app.bcorder.platform_enhance.SaleOrderTag;
import com.epoch.app.crb2btradecenter.domain.order.dto.QueryByOrderNosV2Request;
import com.epoch.app.crb2btradecenter.domain.order.model.Order;
import com.epoch.app.crb2btradecenter.domain.orderline.model.OrderLine;
import com.epoch.app.crb2btradecenter.enums.OrderStatus;
import com.epoch.app.mnordercenter.model.dto.OrderAtomSubmitResponse;
import com.epoch.app.mnordercenter.model.dto.SalesOrderAtomSubmitResponse;
import com.epoch.app.mnordercenter.orderbaserequest.OrderAtomSubmitRequest;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

/**
 * Chen.mu
 * 2023/5/11
 **/
public abstract class AbstractOrderAtomSubmitService implements OrderAtomSubmitService {
    private static final Log log = Log.getLogger(AbstractOrderAtomSubmitService.class);

    @Resource
    private AtomOrderRepository atomOrderRepository;
    @Resource
    private SendMsgService sendMsgService;
    @Resource
    private AtomOrderQueryRepository atomOrderQueryRepository;

    /**
     * 需要进行消息推送的订单状态
     **/
    static final EnumSet<OrderStatus> checkScItemStatus = EnumSet.of(OrderStatus.BEFORE_SUBMIT, OrderStatus.STAY_PUSH);

    /**
     * 订单行价格限制TAG标
     **/
    static final EnumSet<SaleOrderTag> LINE_PRICE_NO_LIMIT = EnumSet.of(SaleOrderTag.FREE_ORDER, SaleOrderTag.CASH_ORDER,
            SaleOrderTag.EXCHANGE_ORDER, SaleOrderTag.STD_RETURN_ORDER,
            SaleOrderTag.LOGISTIC_RETURN_ORDER,
            SaleOrderTag.DS_STD_RETURN_ORDER);
    /**
     * 价格格式校验
     **/
    static final String UNIT_PRICE_REG = "^[+]?([0-9]+\\.?)?[0-9]+$";

    @Override
    public void printExecConsumerTime() {
        StopWatchUtils.print("AbstractOrderAtomSubmitService#batchsubmit");
    }

    @Override
    public void afterSubmitTransactional(List<AtomOrderDO> orderSubmitList) {
        StopWatchUtils.start(CORE_STOP_WATCH_SEQ, "afterSubmitTransactional");
        //生成销售单对象<主单ID, List<子单ID>>
        Map<String, List<String>> confirmOrderMap = orderSubmitList.stream().collect(
                Collectors.toMap(
                        p -> String.valueOf(p.getSalesOrderId()),
                        p -> p.getOrderLines().stream().map(t -> String.valueOf(t.getId())).collect(Collectors.toList()),
                        (v1, v2) -> v1));
        // 发送消息
        sendMsgService.startTaskAndSendSalesOrderMessage(confirmOrderMap);
        StopWatchUtils.stop();

        //如果300的订单，存在F-B的订单，也需要发送消息
        if (CollUtil.isNotEmpty(orderSubmitList) && ObjectUtil.isNotNull(orderSubmitList.get(0).getFactoryBusinessOrderDO())) {
            StopWatchUtils.start(CORE_STOP_WATCH_SEQ, "afterSubmitGroupTransactional");
            Map<String, List<String>> groupConfirmOrderMap = Maps.newHashMap();

            orderSubmitList.forEach(item -> {
                if (ObjectUtil.isNull(item.getFactoryBusinessOrderDO())) {
                    return;
                }
                groupConfirmOrderMap.put(String.valueOf(item.getFactoryBusinessOrderDO().getSalesOrderId()), item.getFactoryBusinessOrderDO().getOrderLines().stream().map(t -> String.valueOf(t.getId())).collect(Collectors.toList()));
            });
            if (CollUtil.isNotEmpty(groupConfirmOrderMap)) {
                sendMsgService.startTaskAndSendSalesOrderMessage(groupConfirmOrderMap);
            }
            StopWatchUtils.stop();
        }
    }

    @Override
    public List<AtomOrderDO> querySalesOrder(List<OrderAtomSubmitRequest> orderRequestList) {
        log.info("SalesOrderAtomSubmitServiceImpl#querySalesOrder request={}", orderRequestList);

        // 按照 来源+业态+业务编码分组
        Map<String, List<OrderAtomSubmitRequest>> reqMap = Optional.ofNullable(orderRequestList).orElse(Lists.newArrayList())
                .stream()
                .collect(Collectors.groupingBy(p ->
                        String.format("%s_%s_%s", p.getFromSys(), p.getBusinessType(), p.getBusinessUnitCode())));
        log.info("SalesOrderAtomSubmitServiceImpl#querySalesOrder reqMap={}", reqMap);

        List<AtomOrderDO> responseList = Lists.newArrayList();

        reqMap.forEach((groupKey, reqList) -> {
            log.info("SalesOrderAtomSubmitServiceImpl#querySalesOrder reqList={}", reqList);
            List<String> orderIds = reqList.stream().map(OrderAtomSubmitRequest::getSalesOrderNo).distinct()
                    .collect(Collectors.toList());

            StopWatchUtils.start(CORE_STOP_WATCH_SEQ, "queryByOrderBizIds");
            QueryByOrderNosV2Request request = new QueryByOrderNosV2Request();
            request.setBusinessType(Integer.parseInt(reqList.get(0).getBusinessType()));
//            request.setBusinessUnitCode(reqList.get(0).getBusinessUnitCode());
            request.setSalesOrderNo(orderIds);
            request.setBusinessUnitOutCode(reqList.get(0).getBusinessUnitCode());
            List<AtomOrderDO> orderSDOS = atomOrderQueryRepository.queryByOrderBizIds(request, true);
            StopWatchUtils.stop();

            StopWatchUtils.start(CORE_STOP_WATCH_SEQ, "getOrderDO");
            List<AtomOrderDO> orderDO = getOrderDO(orderSDOS, reqList);
            StopWatchUtils.stop();

            //如果是一盘货订单，需要查询出关联的F-B订单
            OrderAtomSubmitRequest orderAtomSubmitRequest = reqList.get(0);
            if (OrderCategoryEnum.STOCK.getCode().equals(orderAtomSubmitRequest.getOrderCategoryCode())) {
                StopWatchUtils.start(CORE_STOP_WATCH_SEQ, "queryByRelationOrderBizIds");
                List<String> groupOrderIds = Lists.newArrayList();
                orderSDOS.forEach(it -> groupOrderIds.add(it.getOrder().getRelationNo()));
                QueryByOrderNosV2Request groupRequest = new QueryByOrderNosV2Request();
                groupRequest.setBusinessType(Integer.parseInt(orderAtomSubmitRequest.getBusinessType()));
                groupRequest.setSalesOrderNo(groupOrderIds);
                groupRequest.setBusinessUnitOutCode(orderAtomSubmitRequest.getBusinessUnitCode());
                //查询关联的F-B订单
                List<AtomOrderDO> groupOrderSDOS = atomOrderQueryRepository.queryByOrderBizIds(groupRequest, true);
                StopWatchUtils.stop();

                //更换参数,用于判断数据库不存在的数据
                StopWatchUtils.start(CORE_STOP_WATCH_SEQ, "getGroupOrderDO");
                List<OrderAtomSubmitRequest> requestList = Lists.newArrayList();
                groupOrderSDOS.forEach(item -> {
                    OrderAtomSubmitRequest tempRequest = new OrderAtomSubmitRequest();
                    tempRequest.setSalesOrderNo(item.getOrder().getOrderBizId());
                    requestList.add(tempRequest);
                });
                List<AtomOrderDO> groupOrderDO = getOrderDO(groupOrderSDOS, requestList);
                StopWatchUtils.stop();

                //Map key = B-b的relationNo value = AtomOrderDO
                StopWatchUtils.start(CORE_STOP_WATCH_SEQ, "setFactoryBusinessOrderDO");
                Map<String, AtomOrderDO> groupOrderDOMap = Maps.newHashMap();
                groupOrderDO.forEach(it -> {
                    //关联单号是B-b的ord_biz_id
                    String relationNo = it.getOrder().getRelationNo();
                    groupOrderDOMap.put(relationNo, it);
                });
                orderDO.forEach(it -> {
                    it.setFactoryBusinessOrderDO(groupOrderDOMap.get(it.getSalesOrderNo()));
                });
                StopWatchUtils.stop();
            }
            responseList.addAll(orderDO);
        });
        log.info("SalesOrderAtomSubmitServiceImpl#querySalesOrder response={}", JSON.toJSONString(responseList));
        return responseList;
    }

    private List<AtomOrderDO> getOrderDO(List<AtomOrderDO> orderSDOS, List<OrderAtomSubmitRequest> reqList) {
        List<AtomOrderDO> responseList = Lists.newArrayList();
        List<String> dbSalesOrders = new ArrayList<>();
        if (CollectionUtils.isEmpty(orderSDOS)) {
            switch (getOrderTag()) {
                case "exchange":
                    throw new FunctionException("OC-03-001-01-15-008", reqList.get(0).getSalesOrderNo());
                case "normal":
                    throw new FunctionException("OC-01-001-01-16-016", reqList.get(0).getSalesOrderNo());
                case "return":
                    throw new FunctionException("OC-02-001-01-15-008", reqList.get(0).getSalesOrderNo());
            }
        }
        for (AtomOrderDO orderSDO : orderSDOS) {
            // 过滤非本接口类型的订单，防止串用
            switch (getOrderTag()) {
                case "exchange":
                    if (!"exchange".equals(orderSDO.getOrder().getOrderTag())) {
                        throw new FunctionException("OC-03-001-01-15-008", orderSDO.getOrder().getOrderBizId());
                    }
                    break;
                case "normal":
                    if (!"normal".equals(orderSDO.getOrder().getOrderTag())) {
                        throw new FunctionException("OC-01-001-01-16-016", orderSDO.getOrder().getOrderBizId());
                    }
                    break;
                case "return":
                    if (!"return".equals(orderSDO.getOrder().getOrderTag()) || !orderSDO.getOrder().getOrderCategoryCode().equals(reqList.get(0).getOrderCategoryCode())) {
                        throw new FunctionException("OC-02-001-01-15-008", orderSDO.getOrder().getOrderBizId());
                    }
                    break;
            }

            // 记录数据库能查到的所有订单号
            dbSalesOrders.add(orderSDO.getSalesOrderNo());

            // 过滤掉已取消的子单
            List<OrderLine> orderLineSDOS = orderSDO.getOrderLines().stream()
                    .filter(orderLineSDO -> !Objects.equals(orderLineSDO.getStatus(), OrderStatus.CANCELLED.getCode()))
                    .collect(Collectors.toList());
            orderSDO.setOrderLines(orderLineSDOS);
        }

        // 判断是否包含不存在的单据信息
        List<String> noExistSalesOrders = reqList.stream()
                .map(OrderAtomSubmitRequest::getSalesOrderNo)
                .filter(salesOrderNo -> !dbSalesOrders.contains(salesOrderNo))
                .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(noExistSalesOrders)) {
            switch (getOrderTag()) {
                case "exchange":
                    throw new FunctionException("OC-03-001-01-15-008", StringUtils.join(noExistSalesOrders, "、"));
                case "normal":
                    throw new FunctionException("OC-01-001-01-16-016", StringUtils.join(noExistSalesOrders, "、"));
                case "return":
                    throw new FunctionException("OC-02-001-01-15-008", StringUtils.join(noExistSalesOrders, "、"));
            }
        }

        responseList.addAll(orderSDOS);
        return responseList;
    }

    @Override
    @EpochTransactional(appCode = "mn_order_center", dataSourceCode = "cr_ots", dataSourceType = "app")
    public void submitUpdateTransactional(List<AtomOrderDO> orderSubmitList) {
        if (CollectionUtils.isEmpty(orderSubmitList)) {
            return;
        }

        StopWatchUtils.start(CORE_STOP_WATCH_SEQ, "submitUpdateTransactional");
        CountDownLatch countDownLatch = new CountDownLatch(orderSubmitList.size());
        orderSubmitList.forEach(orderSDO -> ThreadPoolUtil.execute(() -> {
            try {
                orderSDO.getOrder().setStatus(OrderStatus.PUSHING.getCode());
                for (OrderLine orderLine : orderSDO.getOrderLines()) {
                    orderLine.setStatus(OrderStatus.PUSHING.getCode());
                }
                atomOrderRepository.updateOrderStatus(orderSDO);
                if(ObjectUtil.isNotNull(orderSDO.getFactoryBusinessOrderDO())){
                    orderSDO.getFactoryBusinessOrderDO().getOrder().setStatus(OrderStatus.PUSHING.getCode());
                    for (OrderLine orderLine : orderSDO.getFactoryBusinessOrderDO().getOrderLines()) {
                        orderLine.setStatus(OrderStatus.PUSHING.getCode());
                    }
                    atomOrderRepository.updateOrderStatus(orderSDO.getFactoryBusinessOrderDO());
                }
            } catch (Exception e) {
                log.error("AbstractOrderAtomSubmitService#submitUpdateTransactional updateOrder error", e);
            } finally {
                countDownLatch.countDown();
            }
        }));

        try {
            countDownLatch.await();
        } catch (Exception e) {
            log.error("AbstractOrderAtomSubmitService#submitSaveTransactional await error", e);
        }
        StopWatchUtils.stop();
    }

    @Override
    public void paramsInvalidCheck(List<OrderAtomSubmitRequest> requestList, List<OrderAtomSubmitResponse> responseList) {
        StopWatchUtils.start(CORE_STOP_WATCH_SEQ, "paramsInvalidCheck");
        if (Objects.nonNull(getCheckService())) {
            getCheckService().paramsInvalidCheck(requestList, responseList);
        }
        StopWatchUtils.stop();
    }


    @Override
    public void refreshData(List<AtomOrderDO> orderSDOList, List<OrderAtomSubmitRequest> orderList) {
        StopWatchUtils.start(CORE_STOP_WATCH_SEQ, "refreshData");
        // 按照 来源+业态+业务编码+销售单号分组
        Map<String, OrderAtomSubmitRequest> requestMap = orderList.stream()
                .collect(Collectors.toMap(p -> String.format("%s_%s_%s_%s", p.getFromSys(), p.getBusinessType(), p.getBusinessUnitCode(), p.getSalesOrderNo()),
                        p -> p, (v1, v2) -> v1));
        // 更新值
        for (AtomOrderDO atomOrderDO : orderSDOList) {
            Order order = atomOrderDO.getOrder();
            String key = String.format("%s_%s_%s_%s", order.getFromSys(), order.getBusinessType(), order.getBisUnitOutCode(), order.getOrderBizId());
            OrderAtomSubmitRequest mainReq = requestMap.getOrDefault(key, null);
            if (Objects.isNull(mainReq)) {
                continue;
            }
            atomOrderDO.getOrder().setModifier(mainReq.getModifierCode());
            atomOrderDO.getOrder().setModifierName(mainReq.getModifierName());
            atomOrderDO.getOrder().setModifierCode(mainReq.getModifierCode());
            atomOrderDO.getOrder().setModifierName2(mainReq.getModifierName());
            atomOrderDO.getOrder().setGmtModified(new Date());
            //如果是300的订单，这里会有F-B的订单
            if(ObjectUtil.isNotNull(atomOrderDO.getFactoryBusinessOrderDO())){
                atomOrderDO.getFactoryBusinessOrderDO().getOrder().setModifier(mainReq.getModifierCode());
                atomOrderDO.getFactoryBusinessOrderDO().getOrder().setModifierName(mainReq.getModifierName());
                atomOrderDO.getFactoryBusinessOrderDO().getOrder().setModifierCode(mainReq.getModifierCode());
                atomOrderDO.getFactoryBusinessOrderDO().getOrder().setModifierName2(mainReq.getModifierName());
                atomOrderDO.getFactoryBusinessOrderDO().getOrder().setGmtModified(new Date());
                for (OrderLine orderLine : atomOrderDO.getFactoryBusinessOrderDO().getOrderLines()) {
                    orderLine.setModifierId(mainReq.getModifierCode());
                    orderLine.setModifierName(mainReq.getModifierName());
                    orderLine.setGmtModified(new Date());
                }
            }
            for (OrderLine orderLine : atomOrderDO.getOrderLines()) {
                orderLine.setModifierId(mainReq.getModifierCode());
                orderLine.setModifierName(mainReq.getModifierName());
                orderLine.setGmtModified(new Date());
            }
        }
        StopWatchUtils.stop();
    }

    @Override
    public void checkBizInvalid(List<AtomOrderDO> orderSDOList, List<OrderAtomSubmitResponse> salesOrderAtomSubmitResponses) {
        // 若前置校验存在异常，直接返回，不再进行业务校验
        if (CollectionUtils.isNotEmpty(salesOrderAtomSubmitResponses)) {
            return;
        }

        StopWatchUtils.start(CORE_STOP_WATCH_SEQ, "checkBizInvalid");
        Iterator<AtomOrderDO> iterator = orderSDOList.iterator();
        while (iterator.hasNext()) {
            AtomOrderDO order = iterator.next();
            if (!checkScItemStatus.contains(OrderStatus.of(order.getOrder().getStatus()))) {
                appendFailMsg(salesOrderAtomSubmitResponses, order.getOrder(), "OC-01-001-01-16-053", "当前操作与订单可执行操作不匹配");
                iterator.remove();
                continue;
            }
            if (CollectionUtils.isEmpty(order.getOrderLines())) {
                appendFailMsg(salesOrderAtomSubmitResponses, order.getOrder(), "OC-01-003-01-16-005", "没有子单不允许提交");
                iterator.remove();
                continue;
            }
            for (OrderLine orderLineSDO : Optional.ofNullable(order.getOrderLines()).orElse(Lists.newArrayList())) {
                String unitPrice = orderLineSDO.getUnitPrice();
                if (LINE_PRICE_NO_LIMIT.contains(SaleOrderTag.of(order.getOrder().getOrderType()))) {
                    continue;
                }
                if (StringUtils.isBlank(unitPrice)) {
                    appendFailMsg(salesOrderAtomSubmitResponses, order.getOrder(), "OC-01-003-01-16-006", "货品价格为空不允许提交");
                    iterator.remove();
                    break;
                }
                if (!StringUtils.defaultString(unitPrice, "").matches(UNIT_PRICE_REG)) {
                    appendFailMsg(salesOrderAtomSubmitResponses, order.getOrder(), "OC-01-003-01-16-007", "货品价格为负数不允许提交");
                    iterator.remove();
                    break;
                }
            }
        }
        StopWatchUtils.stop();
    }

    void appendFailMsg(List<OrderAtomSubmitResponse> responses, Order order, String errorCode, String errorMsg) {
        SalesOrderAtomSubmitResponse salesOrderAtomSubmitResponse = new SalesOrderAtomSubmitResponse();
        salesOrderAtomSubmitResponse.setSalesOrderNo(order.getOrderBizId());
        salesOrderAtomSubmitResponse.setErrorCode(errorCode);
        salesOrderAtomSubmitResponse.setMessage(errorMsg);
        responses.add(salesOrderAtomSubmitResponse);
    }
}
